# -*- coding: utf-8 -*-
"""
Created on Mon Sep 27 21:55:29 2021

@author: think
"""



E = [32, 1, 2, 3, 4, 5, 
     4, 5, 6, 7, 8, 9, 
     8, 9, 10, 11, 12, 13, 
     12, 13, 14, 15, 16, 17, 
     16, 17, 18, 19, 20, 21, 
     20, 21, 22, 23, 24, 25, 
     24, 25, 26, 27, 28, 29, 
     28, 29, 30, 31, 32, 1]


def initSbox():
    S1 = [[14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7], 
         [0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8], 
         [4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0], 
         [15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13]]
    
    S2 = [[15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10], 
          [3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5], 
          [0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15], 
          [13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9]]
    
    S3 = [[10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8], 
          [13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1], 
          [13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7], 
          [1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12]]
    
    S4 = [[7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15], 
          [13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9], 
          [10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4], 
          [3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14]]
    
    S5 = [[2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9], 
          [14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6], 
          [4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14], 
          [11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3]]
    
    S6 = [[12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11], 
          [10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8], 
          [9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6], 
          [4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13]]
    
    S7 = [[4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1], 
          [13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6], 
          [1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2], 
          [6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12]]
    
    S8 = [[13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7], 
          [1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2], 
          [7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8], 
          [2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11]]
    
    S = [S1, S2, S3, S4, S5, S6, S7, S8]
    
    return S


def initPbox():
    P = [16, 7, 20, 21, 
         29, 12, 28, 17, 
         1, 15, 23, 26, 
         5, 18, 31, 10, 
         2, 8, 24, 14, 
         32, 27, 3, 9, 
         19, 13, 30, 6, 
         22, 11, 4, 25]
    
    return P
    

def getlc(Sq):
    Str_l = str(Sq[0]) + str(Sq[5])
    Str_c = str(Sq[1]) + str(Sq[2]) + str(Sq[3]) + str(Sq[4])
    
    return int(Str_l, 2), int(Str_c, 2)


def choiceExtension(M):
    temp = []
    for i in range(len(E)):
        temp.append(M[E[i] - 1])
    
    return temp


#要求M和key为int列表
def keyEncryption(M, key):
    temp = []
    for i in range(len(M)):
        temp.append(M[i] ^ key[i])
    
    return temp


def sboxReplacement(M, S):
    temp = []
    
    for i in range(8):
        l, c = getlc(M[6 * i : 6 * (i+1)])
        mid = S[i][l][c]
        temp.extend(list('{:0>4b}'.format(mid)))
    
    for i in range(len(temp)):
        temp[i] = int(temp[i])
        
    return temp

    
def pboxReplacement(M, P):
    temp = []
    for i in range(len(P)):
        temp.append(M[P[i] - 1])
    
    return temp


def iterTransform(M, keys):
    #加载S盒
    S = initSbox()
    P = initPbox()
    #初始化list以存储所有的L和R;初始化计数器
    L = []
    R = []
    rounds = 0
    #加载L0和R0
    L.append(M[:32])
    R.append(M[32:])
    
    while(rounds < 16):
        R_pre = R[rounds]
        L_pre = L[rounds]
        R_cur = R_pre
        
        temp = []
        temp2 = []
        
        R_cur = choiceExtension(R_cur)
        R_cur = keyEncryption(R_cur, keys[rounds])
        R_cur = sboxReplacement(R_cur, S)
        R_cur = pboxReplacement(R_cur, P)
        
        L.append(R_pre)
        for i in range(len(L_pre)):
            L_pre[i] = R_cur[i] ^ L_pre[i]
            temp.append(str(L_pre[i]))
            temp2.append(str(R_pre[i]))
        
        #以下内容可以输出迭代加密的中间状态
        '''
        #显示Ki
        print('Keys:')
        print(keys[rounds])
        '''
        '''
        #显示Ri
        print('R'+str(rounds))
        for i in range(len(temp) // 4):
            x = ''.join(temp[i * 4 : (i+1) * 4])
            print('{:x}'.format(int(x, 2)), end = '')
        print()
        '''
        '''
        #显示Li
        print('L'+str(rounds))
        for i in range(len(temp2) // 4):
            x = ''.join(temp2[i * 4 : (i+1) * 4])
            print('{:x}'.format(int(x, 2)), end = '')
        print()
        print()
        '''
        '''
        #显示每轮加密结果
        tempall = temp2 + temp
        print('Round'+str(rounds))
            
        for i in range(len(tempall) // 4):
            x = ''.join(tempall[i * 4 : (i+1) * 4])
            print('{:x}'.format(int(x, 2)), end = '')
        print()
        '''
        R.append(L_pre)
        
        rounds += 1
        
    return L[15] + R[15]